#include "ringpatternmanager.h"

RingPatternManager::RingPatternManager()
{
	vibPatternItem = "";
	ledPatternItem = "";
	// add default Pulse pattern
	vibList["Pulse"] = getPulsePattern();
	deviceCount = 0;
	// constructe device manager

	blueLedManager = new DeviceManager("/sys/class/leds/gta02-power:blue", 0);
	QObject::connect(blueLedManager, SIGNAL(terminateSignal()), 
					 this, SLOT(terminationListener()));
	QObject::connect(blueLedManager, SIGNAL(vibrationSignal(bool, int)), 
					 this, SLOT(vibrationListener(bool, int)));

	orgLedManager = new DeviceManager("/sys/class/leds/gta02-power:orange", 1);
	QObject::connect(orgLedManager, SIGNAL(terminateSignal()), 
					 this, SLOT(terminationListener()));	
	QObject::connect(orgLedManager, SIGNAL(vibrationSignal(bool, int)), 
					 this, SLOT(vibrationListener(bool, int)));

	redLedManager = new DeviceManager("/sys/class/leds/gta02-aux:red", 2);
	QObject::connect(redLedManager, SIGNAL(terminateSignal()), 
					 this, SLOT(terminationListener()));
	QObject::connect(redLedManager, SIGNAL(vibrationSignal(bool, int)), 
					 this, SLOT(vibrationListener(bool, int)));

	vibrationManager = new DeviceManager("/sys/class/leds/neo1973:vibrator", 3);
	QObject::connect(vibrationManager, SIGNAL(terminateSignal()), 
					 this, SLOT(terminationListener()));
	QObject::connect(vibrationManager, SIGNAL(vibrationSignal(bool, int)), 
					 this, SLOT(vibrationListener(bool, int)));
}



RingPatternManager::~RingPatternManager()
{
	// destroy the threads
	vibrationManager->~DeviceManager();
	redLedManager->~DeviceManager();
	blueLedManager->~DeviceManager();
	orgLedManager->~DeviceManager();
}

/**
 * Add a pattern to the pattern list.
 * @param patterName the file name (excluding extension) of a pattern.
 * @param device a static varible indicating the device for vibrating.
 *				 NeoVibratePattern::VIBRATION, NeoVibratePattern::LED
 */
void RingPatternManager::addPattern(QString patternName, Device device)
{	
	switch (device) {
	case VIBRATION:
		addVibrationPattern(patternName);
		break;
	case LED:
		addLedPattern(patternName);
		break;
	default:
		qDebug() << "Not supported device";
		break;
	}
	
}

/**
 *
 */
void RingPatternManager::addVibrationPattern(QString patternName)
{	
	qDebug() << "RingPatternManager::addVibrationPattern()" << patternName;
	//qDebug() << "adding vibration pattern" << patternName << "......";
	QDir dir = QDir::home();//current()
	if (!dir.cd("Documents_PC")) {
		qDebug() << "Directory \"Documents\" does not exist";
		return;
	}
	//qDebug() << "open file" << patternName;
	QFile file(dir.filePath(patternName));
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
		qDebug() << "Can not open file" << patternName;
		return;
	}
	QTextStream input(&file);
	//=================================
	QList<int> pattern;
	int i = 0;
	while (!input.atEnd()) {
		i++;
		QString line = input.readLine();
    	QStringList fields = line.split(",");
		//qDebug() << line << fields.size();
		if (fields.size() > 1 && fields.size() != 2) {
			qDebug() << "Invalid number of pattern fields at line" << i;	
			return;
		} else if (fields.size() == 1) {				
			if (!fields.at(0).isEmpty()) {
				qDebug() << "Invalid number of pattern fields at line" << i;
				return;
			}
			//qDebug() << "Skip empty line" << i;
			continue;
		}
		bool ok1, ok2;
		int strength = fields.at(0).toInt(&ok1, 10);
		int duration = fields.at(1).toInt(&ok2, 10);
		if (ok1 && ok2) {
			if (strength > 255 && strength < 0) {
				qDebug() << "Pattern not in range at line" << i;
			}
			pattern.append(strength);
			pattern.append(duration);
			//qDebug() << strength << duration;
		} else {
			qDebug() << "Pattern not a number at line" << i;	
			return;
		}			
	}		
	file.close();
	QString name = patternName.left(patternName.length()-4);
	vibList[name] = pattern;
	//qDebug() << "Done!!";
}

void RingPatternManager::addLedPattern(QString patternName)
{	
	//qDebug() << "adding led pattern" << patternName << "......";
	QDir dir = QDir::home();//current()
	if (!dir.cd("Documents")) {
		qDebug() << "Directory \"Documents\" does not exist";
		return;
	}
	//qDebug() << "open file" << patternName;
	QFile file(dir.filePath(patternName));
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
		qDebug() << "Can not open file" << patternName;
		return;
	}
	QTextStream input(&file);
	//=================================
	QList<int> pattern;
	int i = 0;
	while (!input.atEnd()) {
		i++;
		QString line = input.readLine();
    	QStringList fields = line.split(",");
		//qDebug() << line << fields.size();
		if (fields.size() > 1 && fields.size() != 5) {
			qDebug() << "Invalid number of pattern fields at line" << i;	
			return;
		} else if (fields.size() == 1) {				
			if (!fields.at(0).isEmpty()) {
				qDebug() << "Invalid number of pattern fields at line" << i;
				return;
			}
			qDebug() << "Skip empty line" << i;
			continue;
		}
		bool ok1, ok2, ok3, ok4, ok5;
		int blue = fields.at(0).toInt(&ok1, 10);
		int org = fields.at(1).toInt(&ok2, 10);
		int red = fields.at(2).toInt(&ok3, 10);
		int strength = fields.at(3).toInt(&ok4, 10);
		int duration = fields.at(4).toInt(&ok5, 10);
		if (ok1 && ok2 && ok3 && ok4 && ok5) {
			if ((blue !=1 && blue !=0) || (org !=1 && org !=0) ||
				(red !=1 && red !=0) || (strength > 255 && strength < 0)) {
				qDebug() << "Pattern not in range at line" << i;
			}
			pattern.append(blue);
			pattern.append(org);
			pattern.append(red);
			pattern.append(strength);
			pattern.append(duration);
			//qDebug() << blue << org << red << strength << duration;
		} else {
			qDebug() << "Pattern not a number at line" << i;	
			return;
		}			
	}		
	file.close();
	QString name = patternName.left(patternName.length()-4);
	ledList[name] = pattern;
	//qDebug() << "Done!!";
}

/**
 * Setup the pattern for playing.
 *@param patternName the pattern name (pattern file name without extension)
 *@param device VIBRATION of LED
 */
void RingPatternManager::setPattern(QString patternName, Device device)
{
	//qDebug() << "=========== setPattern ===========";
	switch (device) {
	case VIBRATION:		
		vibPatternItem = patternName;
		break;
	case LED:		
		ledPatternItem = patternName;	
		break;
	default:
		qDebug() << "Device not supported exception";
		break;
	}
}

/**
 * Calls managers to play the pattern stored in the value space.
 */
void RingPatternManager::playPattern() 
{
	//qDebug() << "=========== playVibrate ===========";
	QString vib = vibPatternItem;
	QString led = ledPatternItem;
	//qDebug() << "Vibration pattern ->" << vib;
	//qDebug() << "LED pattern ->" << led;
	//qDebug() << "option" << sync;

	QList<int> vibPattern;

	if (vib.compare("Random") == 0) {
		vibPattern = getRandomPattern();
		deviceCount++;
	} else {
		if (!vibList.contains(vib)) {
				qDebug() << "Vibration pattern" << led << "doesn't exist";
		} else {
			vibPattern = vibList[vib];
		}
	}
	vibrationManager->setPattern(vibPattern);
	
	if (sync) {
		redLedManager->setPattern(vibPattern);
		blueLedManager->setPattern(vibPattern);
		orgLedManager->setPattern(vibPattern);
	} else {
		if (led.compare("Random") == 0) {
			redLedManager->setPattern(getRandomPattern());
			blueLedManager->setPattern(getRandomPattern());
			orgLedManager->setPattern(getRandomPattern());
		} else if (led.compare("Pulse") == 0) {
			redLedManager->setPattern(vibList["Pulse"]);
			blueLedManager->setPattern(vibList["Pulse"]);
			orgLedManager->setPattern(vibList["Pulse"]);
		} else {			
			if (!ledList.contains(led)) {
				qDebug() << "LED pattern" << led << "doesn't exist";
			}
			blueLedManager->setPattern(getLedPattern(ledList[led], BLUE));
			orgLedManager->setPattern(getLedPattern(ledList[led], ORG));
			redLedManager->setPattern(getLedPattern(ledList[led], RED));
		}	
	}
	//qDebug() << "===================================";
	startVibrate();	
}

void RingPatternManager::startVibrate()
{
	deviceCount = 4;
	vibrationManager->run();
	redLedManager->run();
	blueLedManager->run();
	orgLedManager->run();
}

/**
 * Calls managers to stop playing pattern.
 */
void RingPatternManager::stopVibrate()
{
	vibrationManager->stop();
	redLedManager->stop();
	blueLedManager->stop();
	orgLedManager->stop();
}

/**
 * Generate a random pattern
 */
QList<int> RingPatternManager::getRandomPattern()
{	
	//qDebug() << "=========== getRandomPattern ===========";
	QList<int> pattern;	
	int strength, duration, pause;
	QTime time(0,0,0);
	qsrand(time.msecsTo(QTime::currentTime())+qrand()%10);
	int totalDuration = 0;
	for (int i=0; i<10; i++) {
		strength = 100 + qrand()%156;
		duration = 50 + qrand()%1951;
		pause = 50 + qrand()%451;
		pattern << strength << duration << 0 << pause;
		totalDuration += duration + pause;
		//qDebug() << strength << duration << endl << 0 << pause;
	}	
	//qDebug()<<"Total Duration:" << totalDuration;
	return pattern;
}

/**
 * Generate defualt pulse pattern.
 */
QList<int> RingPatternManager::getPulsePattern()
{
	//qDebug() << "=========== getPulsePattern ===========";
	QList<int> pattern;	
	for (int i=0; i<14; i++) {
		pattern << 255 << 250 << 0 << 500;
	}
	return pattern;
}

QList<int> RingPatternManager::getLedPattern(QList<int> pattern, COLOUR colour)
{
	//qDebug() << "getLedPattern for " << colour;
	QList<int> ledPattern;
	int rounds = pattern.size()/5;
	for (int i = 0; i<rounds; i++) {
		int round = i * 5;
		int deviceOffset = round + colour;
		int strengthOffset = round + 3;
		int durationOffset = round + 4;
		qDebug()<<i<<deviceOffset<<strengthOffset<<durationOffset;
		int strength = pattern.at(deviceOffset) * pattern.at(strengthOffset);
		int duration = pattern.at(durationOffset);
		ledPattern << strength << duration;
		qDebug() << strength << duration;
	}
	return ledPattern;
}

void RingPatternManager::terminationListener()
{	
	deviceCount--;
	qDebug() << "vibration pattern terminated ->" << deviceCount << "remain";
	if (deviceCount == 0) {
		emit completeSignal();
	}
}

void RingPatternManager::vibrationListener(bool pos, int id)
{	
	//qDebug()<<"g0t vibration signal from device"<<id;
	emit vibrationSignal(pos, id);
}

void RingPatternManager::setSync(int sync)
{
	this->sync = sync;
}
